package com.asdhawaii.ics111game.person;

import com.asdhawaii.ics111game.item.Item;
import java.util.ArrayList;
import java.util.List;

/**
 * A carbon-based living organism of the species homo sapiens.
 * 
 * @author Branden Ogata
 *
 */

public class Person 
{
  /**
   * The name of the Person.
   * 
   */
  private String name;
  
  /**
   * A short description of this Person.
   * 
   */
  private String shortDescription;
  
  /**
   * A long description of this Person.
   * 
   */
  private String longDescription;
  
  /**
   * The items that this Person is carrying.
   * 
   */
  private List<Item> inventory;
  
  /**
   * Indicates if this Person is alive.
   * 
   */
  private boolean alive;
  
  /**
   * An arbitrary measure of the energy of this Person.
   * Should range between 0 and 100; this is something like a percentage of HP.
   * 
   */
  private double energy;
  
  /**
   * Initializes a new Person with the given parameters, setting all others to default values.
   * 
   * @param name The name to assign this new Person.
   * @param shortDescription The short description of this Person.
   * @param longDescription The long description of this Person.
   * 
   */
  
  public Person(String name, String shortDescription, String longDescription)
  {
    this.name = name;
    this.shortDescription = shortDescription;
    this.longDescription = longDescription;
    this.inventory = new ArrayList<Item>();
    this.alive = true;
    this.energy = 100.0;
  }
  
  /**
   * Returns the name of this Person.
   * 
   * @return this.name The name of this Person as a String.
   * 
   */
  
  public String getName()
  {
    return this.name;
  }
  
  /**
   * Returns the short description of this Person.
   * Used in response to a LOOK command.
   * 
   * @return this.shortDescription The description of this Person.
   * 
   */
  
  public String getShortDescription()
  {
    return this.shortDescription;
  }
  
  /**
   * Returns the long description of this Person.
   * Used in response to an EXAMINE command.
   * 
   * @return this.longDescription The verbose description of this Person.
   * 
   */
  
  public String getLongDescription()
  {
    return this.longDescription;
  }
  
  /**
   * Returns a hierarchical list of items that this Person is carrying.
   * Items within items should be indented.
   * 
   * @return contents The items that this Person is carrying.
   * 
   */
  
  public String getInventory()
  {
    String contents = "";
    
    // For each item in inventory
    for (Item i : this.inventory) 
    {
      // Append the item itself
      contents += i + "\n";
      
      // The list of anything within the current item
      String nested = i.getContents();

      // If the item contains any items itself, get that list divided into separate lines
      if (nested != null)
      {
        String[] subItems = nested.split("\n");
        
        // Print each item on a separate line, indented
        for (String s : subItems)
        {
          contents += String.format("  %s%n", s);
        }
      }
    }
    
    return contents;
  }
  
  /**
   * Adds an Item instance to the inventory of this Person if possible.
   * 
   * @param item The Item to put into the inventory of this Person.
   * 
   * @return added A boolean that is true if the parameter was added,
   *                                 false otherwise.
   *                                 
   */
  
  public boolean addItem(Item item)
  {
    boolean added = true;
    
    // When overriding, set specifications
    // For example, a Person should only be able to carry up to a certain mass.
    this.inventory.add(item);
    
    return added;
  }
  
  /**
   * Removes an Item instance from the inventory of this Person if it is present.
   * 
   * @param item A String equal to the name of the Item to remove.
   * 
   * @return target The Item removed from the inventory of this Person;
   *                null if the target was not found.
   *                
   */
  
  public Item removeItem(String item)
  {
    Item target = null;
    
    for (Item i : this.inventory)
    {
      // If the String parameter matches the name of the Item,
      // then the desired Item is in the inventory of this Person
      // and therefore can be removed
      if (item.equals(i.getName()))
      {
        target = i;
      }
    }

    this.inventory.remove(target);
    
    return target;
  }
  
  /**
   * Removes and returns all Item instances from the inventory of this Person.
   * 
   * @return allItems The List<Item> of Item instances that this Person was carrying.
   * 
   */
  
  public List<Item> removeAll()
  {
    List<Item> allItems = new ArrayList<Item>();
    allItems.addAll(this.inventory);
    this.inventory.clear();
    
    return allItems;
  }
  
  /**
   * Indicates if this Person is alive.
   * 
   * @return this.alive A boolean indicating if this Person is alive.
   * 
   */
  
  public boolean isAlive()
  {
    return this.alive;
  }
  
  /**
   * Returns the amount of energy that this Person currently has.
   * 
   * @return this.energy A double indicating the energy of this Person.
   * 
   */
  
  public double getEnergy()
  {
    return this.energy;
  }
  
  /**
   * Updates the energy of this Person with the parameter amount.
   * 
   * @param delta A double indicating how much to change the energy of this Person.
   * 
   */
  
  public void updateEnergy(double delta)
  {
    this.energy += delta;
    
    // If this.energy is now greater than 100, set to 100
    if (this.energy > 100)
    {
      this.energy = 100.0;
    }
    
    // If this.energy is now less than 0, set to 0
    // Note that this technically should kill this Person
    if (this.energy < 0)
    {
      this.energy = 0;
    }
  }
  
  /**
   * Compares this Person to the parameter.
   * 
   * @param obj The object to compare this Person to.
   * 
   * @return isEqual A boolean that is true if this Person is equal to the parameter, 
   *                                   false otherwise.
   * 
   */
  
  @Override
  public boolean equals(Object obj)
  {
    boolean isEqual = false;
    
    if (obj == this)
    {
      isEqual = true;
    }
    else if (obj instanceof Person)
    {
      Person temp = (Person) obj;
      
      // If the names are equal,then the two Person instances are equal
      // Not the best way to determine equality, but it will have to do for now
      if (this.getName().equalsIgnoreCase(temp.getName()))
      {
        isEqual = true;
      }
    }
    
    return isEqual;
  }
  
  /**
   * Returns a hash code based on this Person object.
   * Based on the suggestions in Effective Java, Chapter 3.
   * 
   * @return result An int equal to the hash code for this Person object.
   * 
   */
  
  @Override
  public int hashCode()
  {
    int result = 17;
    int combination = this.name.toLowerCase().hashCode();
    result = 37 * result + combination;
    return result;
  }
  
  /**
   * Compares this Person to another Person object.
   * This comparison is based on the names of each Person.
   * 
   * @param p The Person to compare this Person to.
   * 
   * @return 0 if the objects are equal.
   *         1 if this object is greater than the parameter object.
   *         -1 if this object is less than the parameter object.
   *         
   */
  
  public int compareTo(Person p)
  {
    // If this object is the parameter object, then by definition they are equal
    if (this == p)
    {
      return 0;
    }
    
    // Compare names
    if (this.getName().toLowerCase().compareTo(p.getName().toLowerCase()) > 0)
    {
      return 1;
    }
    else if (this.getName().toLowerCase().compareTo(p.getName().toLowerCase()) < 0) 
    {
      return -1;
    }
    
    return 0;
  }
  
  /**
   * Returns a String description of this Person.
   * Essentially returns the name of this Person.
   * 
   * @return A String describing this Person.
   * 
   */
  
  @Override
  public String toString()
  {
    return this.name;
  }  
}
